package jmine.tec.web.servlet.cipher.impl;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.security.InvalidKeyException;
import java.security.Key;

import javax.crypto.Cipher;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import jmine.tec.utils.cripto.cipher.CipherOutputStream;
import jmine.tec.web.servlet.FilterServletOutputStream;

/**
 * Response que faz o 'wrap'
 * 
 * @author takeshi
 */
public final class CipherHttpServletResponse extends HttpServletResponseWrapper {

    private final Cipher cipher;

    private final Key encodeKey;

    private final int chunkSize;

    private PrintWriter writer;

    private FilterServletOutputStream out;

    /**
     * C'tor
     * 
     * @param response {@link HttpServletResponse}
     * @param cipher {@link Cipher}
     * @param encodeKey {@link Key}
     * @param chunkSize int
     */
    public CipherHttpServletResponse(HttpServletResponse response, Cipher cipher, Key encodeKey, int chunkSize) {
        super(response);
        this.cipher = cipher;
        this.encodeKey = encodeKey;
        this.chunkSize = chunkSize;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setContentLength(int len) {
        // ignore content length
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public PrintWriter getWriter() throws IOException {
        writer = new PrintWriter(new OutputStreamWriter(this.getOutputStream(), this.getCharacterEncoding()));
        return writer;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        try {
            final OutputStream delegate = new CipherOutputStream(super.getOutputStream(), this.cipher, this.encodeKey, this.chunkSize);
            out = new FilterServletOutputStream(delegate);
            return out;
        } catch (InvalidKeyException e) {
            throw new IOException(e.getMessage());
        }
    }

    /**
     * Forca o flush do OutputStream ou PrintWriter
     * 
     * @throws IOException e
     */
    public void flushBuffer() throws IOException {
        if (out != null) {
            out.flush();
        }
        if (writer != null) {
            writer.flush();
        }
        super.flushBuffer();
    }

}